package dd.lo.classifier;

import dd.lo.util.ImageUtils;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.FlowPane;
import javafx.scene.text.Text;
import javafx.stage.Stage;
//import org.datavec.image.loader.NativeImageLoader;
//import org.deeplearning4j.nn.multilayer.MultiLayerNetwork;
//import org.deeplearning4j.util.ModelSerializer;
//import org.nd4j.linalg.api.ndarray.INDArray;
//import org.nd4j.linalg.dataset.api.preprocessor.ImagePreProcessingScaler;
import org.opencv.core.*;
import org.opencv.imgcodecs.Imgcodecs;
import org.opencv.imgproc.Imgproc;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public class WrittenNumberClassifier {
//public class WrittenNumberClassifier extends Application {

//    public static void start(String[] args) {
//        launch(args);
//    }

//    private static final int DEFAULT_WIDTH = 1080;
//    private static final int DEFAULT_HEIGHT = 768;
//
//    private static final int IMG_WIDTH = DEFAULT_WIDTH - 20;
//    private static final int IMG_HEIGHT = DEFAULT_HEIGHT - 20;
//
//    private static final int PREDICT_IMG_WIDTH = 28;
//    private static final int PREDICT_IMG_HEIGHT = 28;
//
//    private ImageView gImageView;
//    private Text predictResult;
//
//    private boolean gPressed = false;
//
//    private List<Point> gPoints = new ArrayList<>();
//
//    private List<MatOfPoint> gTraces = new ArrayList<>();
//
//    private Mat img;
//
//    private MultiLayerNetwork model;
//
//    private void drawTrace() {
//        Task<Void> task = new Task<Void>() {
//            @Override
//            protected Void call() {
//                img = new Mat(IMG_HEIGHT, IMG_WIDTH, CvType.CV_8UC1, Scalar.all(233));
//                List<MatOfPoint> traces = new ArrayList<>(gTraces);
//                traces.add(new MatOfPoint(gPoints.toArray(new Point[0])));
//                Imgproc.polylines(img, traces, false, Scalar.all(0), 20, Imgproc.LINE_8);
//                MatOfByte buffer = new MatOfByte();
//                Imgcodecs.imencode(".jpeg", img, buffer);
//                Platform.runLater(() -> gImageView.setImage(new Image(new ByteArrayInputStream(buffer.toArray()))));
//                return null;
//            }
//        };
//        new Thread(task).start();
//    }
//
//    private void predict() {
//        Task<Void> task = new Task<Void>() {
//            @Override
//            protected Void call() throws IOException {
//                Mat dst = new Mat();
//                Mat dst1 = new Mat();
//                //图像处理
//                img.copyTo(dst);
//                Core.normalize(dst, dst, 0, 255, Core.NORM_MINMAX);
//                Imgproc.threshold(dst1, dst1, 232, 255, Imgproc.THRESH_BINARY);
//                List<MatOfPoint> contours = new ArrayList<>();
//                Mat hierarchy = new Mat();
//                Imgproc.findContours(dst, contours, hierarchy, Imgproc.RETR_TREE, Imgproc.CHAIN_APPROX_SIMPLE);
//                Rect roi = null;
//                for (int i = 0; i < contours.size(); ++i) {
//                    MatOfPoint contour = contours.get(i);
//                    Rect rect = Imgproc.boundingRect(contour);
//                    //0~3分别表示后一个轮廓、前一个轮廓、父轮廓、内嵌轮廓的索引值
//                    double[] h = hierarchy.get(0, i);
//                    if (h[3] == 0.0) {
//                        //如果这个轮廓是最外围的，则内嵌轮廓的索引值为0
//                        //Draw contour boundingRect
//                        Imgproc.rectangle(dst, rect, new Scalar(0), 1);
//                        roi = rect;
//                        break;
//                    }
//                }
//                if (null != roi) {
//                    int centerX = roi.x + roi.width / 2, centerY = roi.y + roi.height / 2;
//                    int maxLen = Math.max(roi.width, roi.height) + 50, halfMaxLen = maxLen / 2;
//                    int top = Math.max(0, centerY - halfMaxLen);
//                    int left = Math.max(0, centerX - halfMaxLen);
//                    int bottom = Math.min(dst.height() - 1, centerY + halfMaxLen);
//                    int right = Math.min(dst.width() - 1, centerX + halfMaxLen);
//                    roi = new Rect(left, top, right - left, bottom - top);
//                    dst1 = new Mat(dst, roi);
//                }
//                Imgproc.resize(dst1, dst1, new Size(PREDICT_IMG_WIDTH, PREDICT_IMG_HEIGHT), 0, 0, Imgproc.INTER_AREA);
//                Imgproc.threshold(dst1, dst1, 125, 255, Imgproc.THRESH_BINARY_INV);
//                //预测数字
//                ImagePreProcessingScaler scalar = new ImagePreProcessingScaler(0,1);
//                MatOfByte buf = new MatOfByte();
//                Imgcodecs.imencode(".jpeg", dst1, buf);
//                BufferedInputStream inputStream = new BufferedInputStream(new ByteArrayInputStream(buf.toArray()));
//                NativeImageLoader nil = new NativeImageLoader(PREDICT_IMG_HEIGHT, PREDICT_IMG_WIDTH);
//                INDArray imgArray = nil.asRowVector(inputStream);
//                scalar.transform(imgArray);
//                int result = model.predict(imgArray)[0];
//                //显示处理的图像
//                ImageUtils.fitImgSize(dst, IMG_WIDTH, IMG_HEIGHT);
//                MatOfByte buffer = new MatOfByte();
//                Imgcodecs.imencode(".jpeg", dst, buffer);
//                Platform.runLater(() -> {
//                    gImageView.setImage(new Image(new ByteArrayInputStream(buffer.toArray())));
//                    predictResult.setText(String.format("预测结果：%d", result));
//                });
//                return null;
//            }
//        };
//        new Thread(task).start();
//    }
//
//    @Override
//    public void start(Stage stage) throws IOException {
//        model = ModelSerializer.restoreMultiLayerNetwork(new File(Objects.requireNonNull(this.getClass().getResource("/")).getPath() + "minist_model_0.93.zip"));
//        Button predictBtn = new Button("识别数字");
//        predictBtn.setOnMouseClicked(event -> predict());
//        predictResult = new Text();
//        Button clearBtn = new Button("重新绘制");
//        clearBtn.setOnMouseClicked(event -> {
//            gPoints.clear();
//            gTraces.clear();
//            drawTrace();
//        });
//        FlowPane bottomControl = new FlowPane();
//        bottomControl.getChildren().addAll(predictBtn, predictResult, clearBtn);
//        bottomControl.setPrefHeight(50);
//        gImageView = new ImageView();
//        Mat bg = new Mat(IMG_HEIGHT, IMG_WIDTH, CvType.CV_8UC1, Scalar.all(233));
//        MatOfByte buffer = new MatOfByte();
//        Imgcodecs.imencode(".jpeg", bg, buffer);
//        gImageView.setImage(new Image(new ByteArrayInputStream(buffer.toArray())));
//        gImageView.setOnMouseDragged(e -> {
//            if (gPressed) {
//                gPoints.add(new Point(e.getX(), e.getY()));
//                drawTrace();
//            }
//        });
//        gImageView.setOnMousePressed(event -> {
//            gPressed = true;
//        });
//        gImageView.setOnMouseReleased(event -> {
//            gPressed = false;
//            gTraces.add(new MatOfPoint(gPoints.toArray(new Point[0])));
//            gPoints.clear();
//            drawTrace();
//        });
//        BorderPane centerPane = new BorderPane();
//        centerPane.setPadding(new Insets(10));
//        centerPane.setCenter(gImageView);
//        BorderPane root = new BorderPane();
//        root.setCenter(centerPane);
//        root.setBottom(bottomControl);
//        Scene scene = new Scene(root, DEFAULT_WIDTH, DEFAULT_HEIGHT + 70);
//        stage.setScene(scene);
//        stage.setTitle("Written Number Classifier");
//        stage.setResizable(false);
//        stage.show();
//    }
}
